#include "webbot_ie.hpp"
#include <itoken.hpp>
#include <input_interface.hpp>

webbot_ie::webbot_ie(const char* _dispatch_struct_filename): iwebbot(_dispatch_struct_filename)
{
	webbrowser =NULL;
	init_web_browser();
}


bool webbot_ie::init_web_browser()
{	
	if(webbrowser == NULL)
	{
		HRESULT hr = CoInitialize(NULL);

		if(SUCCEEDED(hr) && SUCCEEDED(hr = CoCreateInstance (CLSID_InternetExplorer, NULL, CLSCTX_LOCAL_SERVER, 
				IID_IWebBrowser2, (LPVOID *)&webbrowser)))	//Create an Instance of web browser
		{
			return true;
		}

		return false;
	}
	return true;
}


bool webbot_ie::open_URL() 				 
{
	dispatch_struct dispatch_info = this->get_dispatch_struct();
	std::string _url = dispatch_info.get_URI();

	if(webbrowser != NULL && !_url.empty())	//Create an Instance of web browser
	{
		CString mURL(_url.c_str());
		VARIANT vaURL;
		VariantInit(&vaURL);
		vaURL.vt = VT_BSTR;
		vaURL.bstrVal = mURL.AllocSysString();	

		BSTR bstrHeaders = NULL;
        VARIANT vFlags = {0},
            vTargetFrameName = {0},
            vPostData = {0},
            vHeaders = {0};


		if(dispatch_info.post_url_encoded_data())
		{
			bstrHeaders = SysAllocString(
            L"Content-Type: application/x-www-form-urlencoded\r\n");
			if (!bstrHeaders)
			{
				if (bstrHeaders) SysFreeString(bstrHeaders);
				return false;
			}

			V_VT(&vHeaders) = VT_BSTR;
			V_BSTR(&vHeaders) = bstrHeaders;
		 
			bool hr = get_post_data(&vPostData);
		}

		 HRESULT hr = webbrowser->Navigate2(&vaURL,&vFlags,&vTargetFrameName,&vPostData,&vHeaders) ; //Open the mail login page	
		set_visible(true);

		wait_ready_state(); // waiting page to load completely
	
		if(SUCCEEDED(hr) && wait_ready_state_interactive()) 
			return true;
	}

	if(_url.empty()) return true;

	return false;
}



IDispatch* webbot_ie::get_dispatch_interface()
{
	IDispatch* pDisp;

	if(webbrowser !=NULL)
	{
		HRESULT hr=webbrowser->get_Document(&pDisp);
		if(SUCCEEDED(hr)) //Get the underlying document object of the browser
			return pDisp;
	}		
	return pDisp;
}


IHTMLDocument2* webbot_ie::get_HTML_document_interface(IDispatch* pDisp)
{
	IHTMLDocument2* pHTMLDocument2;

	if (pDisp != NULL )
	{		
		HRESULT hr = pDisp->QueryInterface( IID_IHTMLDocument2, (void**)&pHTMLDocument2 );
		if(SUCCEEDED(hr))	//Ask for an HTMLDocument2 interface
			return pHTMLDocument2;
	}
	return pHTMLDocument2;
}


IHTMLElementCollection* webbot_ie::get_HTML_element_collection(IHTMLDocument2* pHTMLDocument2)
{
	IHTMLElementCollection* pColl;//Enumerate the HTML elements

	if(pHTMLDocument2 != NULL)
	{
		HRESULT hr = pHTMLDocument2->get_all( &pColl );
		if(SUCCEEDED(hr))
			return pColl;
	}
	return pColl;
}


IHTMLInputElement* webbot_ie::get_HTML_input_element(const IID _IID_IHTMLInputElement, long& _i, long const& _celem, 
									   IHTMLElementCollection* pColl, IHTMLElement** _pElem)
{	
	IHTMLInputElement* pInputElement =NULL;
	HRESULT hr;	
	
	for ( long maxElem = _celem; _i< maxElem; _i++ )	//loop through each element
	{

		VARIANT varIndex;
		varIndex.vt = VT_UINT;
		varIndex.lVal = _i;

		VARIANT var2;
		VariantInit( &var2 );
		IDispatch* pDisp =NULL; 

		if(SUCCEEDED(hr = pColl->item( varIndex, var2, &pDisp )) && pDisp != NULL) //Get an element
		{
			IHTMLElement* pElem =NULL;
			if(SUCCEEDED(hr = pDisp->QueryInterface( //Ask for an HTMLElemnt interface
									IID_IHTMLElement,(void **)&pElem)))
			{
				BSTR bstr;
				CString strTag;

				if(SUCCEEDED(hr = pElem->get_tagName(&bstr)))	//Get the tag name for the element
				{
					strTag = bstr;							
				}

				pInputElement = NULL;
				if(SUCCEEDED(hr = pDisp->QueryInterface(_IID_IHTMLInputElement, 
                                        (void **)&pInputElement )))
				{
					* _pElem = pElem;
					//pElem->Release();
					pDisp->Release();
					break;									
				}
			} //IHTMLElement
			pElem->Release();
		}// item collection	
		pDisp->Release();
	} // loop through each element
			
	return pInputElement;
}

template <class T> T* webbot_ie::get_HTML_input_template_element(std::string const& _name, 
			IHTMLElementCollection* pColl, IHTMLElement** _pElem, const IID _IID_IHTMLInputElement)
{
	T* pInputElement = NULL;

	if (pColl != NULL)
	{		
		long celem;		
		HRESULT hr;

		if(SUCCEEDED(hr = pColl->get_length( &celem )))	// find the count of the elements
		{
			CString cstr, mName(_name.c_str());
			long j=0;
			do
			{		
				BSTR bstr;
				IHTMLElement* pElem  = NULL;
				if(pInputElement = (T*) get_HTML_input_element(_IID_IHTMLInputElement, j, celem, pColl, &pElem))
				{
					pInputElement->get_name(&bstr);
					cstr = bstr;
					if(cstr == mName)
					{
						* _pElem = pElem;
						break;
					}
				}
				j++;
			}while( j < celem ); // is this the field we want?
		}
	}

	return pInputElement;

}

IHTMLElement* webbot_ie::get_element_byID(std::string const& _szId, IHTMLElementCollection *pColl)
{
	IHTMLElement* pElem =NULL;
	CString szID(_szId.c_str());
    BSTR bstrID = szID.AllocSysString();

    VARIANT varName, varIndex;
    varName.vt = VT_BSTR;
    varName.bstrVal = bstrID;
    varIndex.vt = VT_I4;
    varIndex.intVal = 0;

    IDispatch* pDisp; 
    HRESULT hr = pColl->item(varName, varIndex, &pDisp);
    if (SUCCEEDED(hr) && pDisp)
    {
        hr = pDisp->QueryInterface( IID_IHTMLElement, (void**)&pElem );
    }
	    
    ::SysFreeString(bstrID);

	return (FAILED(hr) ? NULL: pElem);
}

IHTMLElement* webbot_ie::get_element_by_outer_HTML(std::string const& _szOuterHTML, IHTMLElementCollection *pColl)
{
	CString szOuterHTML(_szOuterHTML.c_str());
    IHTMLElement* pElem = NULL;
    HRESULT hr = 1;
    long len;
    pColl->get_length(&len);

    for (int i = 0; i < len; i++)
    {
        VARIANT varName, varIndex;
        varName.vt = VT_UINT;
        varName.lVal = i;
        varIndex.vt = VT_I4;
        varIndex.intVal = 0;

        IDispatch* pDisp; 
        hr = pColl->item(varName, varIndex, &pDisp);
        if (SUCCEEDED(hr))
        {
            hr = pDisp->QueryInterface( IID_IHTMLElement, (void**)&pElem);
            if (SUCCEEDED(hr))
            {
                BSTR tempOuterHTML;
                hr = pElem->get_outerHTML(&tempOuterHTML);

                if (SUCCEEDED(hr) && (szOuterHTML == tempOuterHTML))
                {
                    ::SysFreeString(tempOuterHTML);                    
					return pElem;
                }
                ::SysFreeString(tempOuterHTML);
            }			
        }
		pElem =NULL;
    }

    return pElem;
}


IHTMLElement* webbot_ie::get_element_by_name(std::string const& _szOuterHTML, IHTMLElementCollection *pColl)
{
	CString szOuterHTML(_szOuterHTML.c_str());
    IHTMLElement *pElem = NULL;
    HRESULT hr = 1;
    long len;
    pColl->get_length(&len);

    for (int i = 0; i < len; i++)
    {
        VARIANT varName, varIndex;
        varName.vt = VT_UINT;
        varName.lVal = i;
        varIndex.vt = VT_I4;
        varIndex.intVal = 0;

        IDispatch* pDisp; 
        hr = pColl->item(varName, varIndex, &pDisp);
        if (SUCCEEDED(hr))
        {
            hr = pDisp->QueryInterface( IID_IHTMLElement, (void**)&pElem);
            if (SUCCEEDED(hr))
            {
                BSTR tempOuterHTML;
                hr = pElem->get_outerHTML(&tempOuterHTML);

                if (SUCCEEDED(hr) && (szOuterHTML == tempOuterHTML))
                {
                    ::SysFreeString(tempOuterHTML);                 
					return pElem;
                }
                ::SysFreeString(tempOuterHTML);
            }							
        }
		pElem=NULL;
    }

    return pElem;
}

IHTMLInputButtonElement* webbot_ie::get_HTML_input_button_element(std::string const& _name, IHTMLElementCollection* pColl, IHTMLElement** _pElem)
{
	IHTMLInputButtonElement* pInputButtonElement = get_HTML_input_template_element<IHTMLInputButtonElement>(_name, pColl, _pElem, 	IID_IHTMLInputButtonElement);
	return pInputButtonElement;
}

IHTMLInputTextElement* webbot_ie::get_HTML_input_text_element(std::string const& _name, IHTMLElementCollection* pColl, IHTMLElement** _pElem)
{
	IHTMLInputTextElement* pInputTextElement = get_HTML_input_template_element<IHTMLInputTextElement>(_name, pColl, _pElem, IID_IHTMLInputTextElement);
	return pInputTextElement;
}

IHTMLInputImage* webbot_ie::get_HTML_input_image(std::string const& _name, IHTMLElementCollection* pColl, IHTMLElement** _pElem)
{
	IHTMLInputImage* pInputImage = get_HTML_input_template_element<IHTMLInputImage>(_name, pColl, _pElem, IID_IHTMLInputImage);
	return pInputImage;
}


IHTMLInputHiddenElement* webbot_ie::get_HTML_input_hidden_element(std::string const& _name, IHTMLElementCollection* pColl, IHTMLElement** _pElem)
{
	IHTMLInputHiddenElement* pInputTextElement = get_HTML_input_template_element<IHTMLInputHiddenElement>(_name, pColl, _pElem, IID_IHTMLInputHiddenElement);
	return pInputTextElement;
}

IHTMLFormElement* webbot_ie::get_HTML_form_element(std::string const& _name, IHTMLElementCollection* pColl, IHTMLElement** _pElem)
{
	IHTMLFormElement* pFormElement = get_HTML_input_template_element<IHTMLFormElement>(_name, pColl, _pElem, IID_IHTMLFormElement);
	return pFormElement;
}

IHTMLInputButtonElement* webbot_ie::get_HTML_button_element(std::string const& _name, IHTMLElementCollection* pColl, IHTMLElement** _pElem)
{
	IHTMLInputButtonElement* pInputButtonElement = get_HTML_input_template_element<IHTMLInputButtonElement>(_name, pColl, _pElem, IID_IHTMLInputButtonElement);
	return pInputButtonElement;
}


/*
htmlInputButton	= 1,
	htmlInputCheckbox	= 2,
	htmlInputFile	= 3,
	htmlInputHidden	= 4,
	htmlInputImage	= 5,
	htmlInputPassword	= 6,
	htmlInputRadio	= 7,
	htmlInputReset	= 8,
	htmlInputSelectOne	= 9,
	htmlInputSelectMultiple	= 10,
	htmlInputSubmit	= 11,
	htmlInputText	= 12,
	htmlInputTextarea	= 13,
	htmlInputRichtext	= 14,
	htmlInput_Max
*/


bool webbot_ie::submit(IHTMLFormElement* pForm)
{
	if(pForm != NULL)
	{
		//We will submit the form that contains the button than clicking it
		//This will send the all the information in correct format		
		pForm->submit(); //Submit the form													
		pForm->Release();
		return true;			
	}
	return false;
}

bool webbot_ie::submit(IHTMLInputImage* pImageButton)
{
	if(pImageButton !=NULL)
	{
		((IHTMLElement*)pImageButton)->click();
		pImageButton->Release();
		return true;
	}	
	return false;
}	
				

void webbot_ie::wait_ready_state()
{
	
	if(webbrowser != NULL)
	{
		HRESULT hr;
		READYSTATE readyState(READYSTATE_UNINITIALIZED);


		do
		{		
			hr = webbrowser->get_ReadyState(&readyState);
		} while (SUCCEEDED(hr) && 
			readyState != READYSTATE_COMPLETE && 
			readyState != READYSTATE_INTERACTIVE
			); //This while loop makes sure that the page is fully loaded before we go to the next page		
		
	}

	
}

void webbot_ie::dispose()
{
	if(webbrowser != NULL)
	{
		webbrowser->Release();
		CoUninitialize();						
	}		
}



bool webbot_ie::set_visible(bool const& _isVisible)
{
	VARIANT_BOOL pBool=_isVisible;
	if(webbrowser!=NULL)
	{
		HRESULT hr = webbrowser->put_Visible( pBool ) ; // Comment out this line if you dont want the browser to be displayed
		if(SUCCEEDED(hr)) return true;
	}
	return false;
}


void webbot_ie::dispatch()
{		

	do
	{	
		if(!open_URL())
			break;

		if(!get_dispatch_struct().post_url_encoded_data())
		{
			if(IDispatch* pDisp = get_dispatch_interface())
			{
				if(IHTMLDocument2* pIHTMLDocument2 = get_HTML_document_interface(pDisp)) //Ask for an HTMLElemnt interface
				{
					if(IHTMLElementCollection* pIHTMLElementCollection = get_HTML_element_collection(pIHTMLDocument2))
					{									
						perform_input_actions(pIHTMLElementCollection);							
						pIHTMLElementCollection->Release();
					}
					pIHTMLDocument2->Release();
				}
				pDisp->Release();
			}
		}

		wait_ready_state(); // waiting page to load completely	

		if(!wait_ready_state_interactive())
			break;		

	} while(get_next_dispatch_struct());

	dispose();
}



void webbot_ie::perform_input_actions(IHTMLElementCollection* pIHTMLElementCollection)
{
				
	dispatch_struct dispatch_info = get_dispatch_struct(); 
	std::vector< std::string > element_name = dispatch_info.get_input_element_name();
	std::vector< dispatch_struct::input_type > element_type = dispatch_info.get_input_element_type();	
	std::vector< std::string > element_value = dispatch_info.get_input_element_value();
	std::vector< std::string > encryption_config = dispatch_info.get_input_element_encryption();
	std::vector< dispatch_struct::encryption_task > encryption_tsk = dispatch_info.get_input_encryption_task_type();

	for(unsigned int j =0, k=0, l=0; j < element_name.size(); j++)
	{
		switch(element_type[j])
		{
		case dispatch_struct::TEXT:
			if(element_value.size())
			{
				k = min(element_value.size()-1, k);
				on_input_text(element_name[j], element_value[k++], pIHTMLElementCollection);
			}
			break;
		case dispatch_struct::HIDDEN:
			k = max(0, min(encryption_config.size()-1, k));
			l = max(0, min(encryption_tsk.size()-1, l));
			on_input_hidden(element_name[j], encryption_config[k++], encryption_tsk[l++], pIHTMLElementCollection);
			break;
		case dispatch_struct::PASSWORD:	
			k = max(0, min(encryption_config.size()-1, k));
			l = max(0, min(encryption_tsk.size()-1, l));
			on_input_password(element_name[j], encryption_config[k++], encryption_tsk[l++], pIHTMLElementCollection);
			break;
		case dispatch_struct::IMAGE:
			on_input_image(element_name[j], pIHTMLElementCollection);
			break;
		case dispatch_struct::BUTTON:
			on_input_button(element_name[j], pIHTMLElementCollection);
			break;
		case dispatch_struct::FORM_ACTION:
			on_form_action(element_name[j], pIHTMLElementCollection);
			break;
		case dispatch_struct::JSCRIPT:
			on_jscript_action(element_name[j]);
			break;
		default: break;
		}
	}
}

//TODO: 

/*
HRESULT SendFiles(CStringArray& aszFile)
{
	//show progress bar
	//SetProgress("???? ?? ????.\r\n\r\n\r\n???? : %d %%", 10);
	ShowStatus(TRUE);
	UpdateData(FALSE);

	CInternetSession inetSession;
	CFtpConnection *pConnection = NULL;

	if(!AfxSocketInit())
	{
		AfxMessageBox(TEXT("Could not initialize the socket."));
		return E_FAIL;
	}
	//ftp connection...
	pConnection = inetSession.GetFtpConnection(IPADDR, USRID, PASSWD);
	if(!pConnection)
	{
		AfxMessageBox(TEXT("Could not establish the connection."));
		pConnection = NULL;
		return E_FAIL;
	}

	//make subdirectory
	BOOL bFound = FALSE;
	if(!m_szUpSubDir.IsEmpty() && m_szUpSubDir.GetLength() > 0)
	{
		CFtpFileFind *pFileFind = new CFtpFileFind(pConnection);
		if(pFileFind->FindFile("."))
		{
			//DWORD dw = GetLastError();
			while(pFileFind->FindNextFile())
			{
				if(!pFileFind->IsDirectory()) continue;
				if(m_szUpSubDir == pFileFind->GetFileName()) bFound = TRUE;
			}
		}
		delete pFileFind;	pFileFind = NULL;

		if(!bFound) pConnection->CreateDirectory(m_szUpSubDir);
		bFound = pConnection->SetCurrentDirectory(m_szUpSubDir);
	}

	//SetProgress("???? ?? ????.\r\n\r\n\r\n???? : %d %%", 30);
	//get local file size
	ULONGLONG dwTotLen = 0, dwUpLen = 0;
	for(int i=0; i<aszFile.GetSize(); i++)
	{
		CFile fLocal(aszFile[i], CFile::modeRead);
		dwTotLen += fLocal.GetLength();
	}
	for(int i=0; i<aszFile.GetSize(); i++)
	{
		//write the remote file
		CInternetFile *fRemote = NULL;
		fRemote = pConnection->OpenFile(aszFile[i].Right(m_szOutFileID.GetLength()+4), GENERIC_WRITE);
		if(!fRemote)
		{
			AfxMessageBox(TEXT("Could not open the remote file."));
			pConnection->Close();
			delete pConnection;	pConnection = NULL;
			return E_FAIL;
		}
		//read the local file
		char szBuffer[1024];
		UINT iRead = sizeof(szBuffer);
		CFile fLocal(aszFile[i], CFile::modeRead);

		while(iRead == sizeof(szBuffer))
		{
			iRead = fLocal.Read(szBuffer, sizeof(szBuffer));
			try
			{
				fRemote->Write(szBuffer, iRead);
			}
			catch(CInternetException *e)
			{
				char message[512];
				e->GetErrorMessage(message,512);
				AfxMessageBox(TEXT("Could not write the remote file."));
				fLocal.Close();
				fRemote->Close();
				delete fRemote; fRemote = NULL;
				pConnection->Close();
				delete pConnection;	pConnection = NULL;

				delete e;
				return E_FAIL;
			}
			//show progress bar
			dwUpLen += (ULONGLONG)iRead;
			int iDone = (int)(dwUpLen * 70 / dwTotLen) + 30;
			//SetProgress("?????????? ???e? ?? ????.\r\n\r\n\r\n???e? : %d %%", iDone);
			UpdateData(FALSE);
		}
		fLocal.Close();
		fRemote->Close();
		delete fRemote; fRemote = NULL;
	}

	//free memory
	pConnection->Close();
	delete pConnection;	pConnection = NULL;

	//hide progress bar
	//SetProgress("???????", 0);
	ShowStatus(FALSE);
	UpdateData(FALSE);

	return S_OK;
}
*/

void webbot_ie::jscript(std::string const& _script, IHTMLDocument2*   pDocument)
{   
    if   (pDocument !=  NULL)   
    {   
		IHTMLWindow2* pHTMLWnd;
        HRESULT hresult = pDocument->get_parentWindow(&pHTMLWnd);   

        if   (SUCCEEDED(hresult))   
        {   
			CString cjs(_script.c_str());
			BSTR   js = cjs.AllocSysString();
            BSTR   l = SysAllocString(L"javascript");
            VARIANT   vtEmpty;
			vtEmpty.vt   =VT_EMPTY;

            pHTMLWnd->execScript(js, l, &vtEmpty); 

			pHTMLWnd->Release();
			SysFreeString(js);
			SysFreeString(l);
			VariantClear(&vtEmpty);
         }   
   }   
}


template <class T> bool webbot_ie::put_input_template_value(std::string const& _str, T* pInputElement)
{
	if(pInputElement != NULL && !_str.empty())
	{
		CString mValue(_str.c_str());
		BSTR bstr = mValue.AllocSysString();

		HRESULT hr = pInputElement->put_value(bstr);
		if(SUCCEEDED(hr)) 
		{
			pInputElement->Release();
			return true;
		}
	}
	return false;
}


bool webbot_ie::on_input_hidden(std::string const &_strName, std::string const& _encryption_config, 
									dispatch_struct::encryption_task& _encryption_tsk, IHTMLElementCollection* pIHTMLElementCollection)
{	
	IHTMLElement* pElem =NULL;	

	if(IHTMLInputHiddenElement* pInputHiddenElement = get_HTML_input_hidden_element(_strName, pIHTMLElementCollection, &pElem))
	{
		pElem->Release();		
		return webbot_ie::on_input_template_hidden<IHTMLInputHiddenElement>(pInputHiddenElement, _encryption_config, _encryption_tsk);
	}

	return false;
							
}

bool webbot_ie::on_input_password(std::string const &_strName, std::string const& _encryption_config, 
									dispatch_struct::encryption_task& _encryption_tsk, IHTMLElementCollection* pIHTMLElementCollection)
{	
	IHTMLElement* pElem =NULL;	

	if(IHTMLInputTextElement* pInputHiddenElement = get_HTML_input_text_element(_strName, pIHTMLElementCollection, &pElem))
	{
		pElem->Release();
		return webbot_ie::on_input_template_hidden<IHTMLInputTextElement>(pInputHiddenElement, _encryption_config, _encryption_tsk);
	}

	return false;
							
}

template <class T> bool webbot_ie::on_input_template_hidden(T* pInputHiddenElement, 
															std::string const& _encryption_config, dispatch_struct::encryption_task& _encryption_tsk)
{
	//IHTMLInputHiddenElement* pInputHiddenElemen;

	libtoken tk_interface(_encryption_config.c_str());
	itoken *tk = tk_interface.getToken();
	
	std::string _strValue;
	std::string _actualCoords;

	switch(_encryption_tsk)
	{
		case dispatch_struct::ENCRYPT:
			if(iwebbot::is_first_change)
			{
				tk->write(get_dispatch_struct().get_dispatch_struct_filename().c_str(), false); // store previous token and...
				tk->write(); // create new one
				iwebbot::is_first_change = false;
			}
			_encryption_tsk = dispatch_struct::DECRYPT;			
		case dispatch_struct::DECRYPT:
			//if(get_dispatch_struct().get_use_ingdirect_pinpad_coords())
			//if(1)
			//{
				//we are supposed to input the sequence of coordinates related to numbers from 0 to 9 in ascending order
				//The first 10 values are the coordinates of the pinpad; whereas the rest of the sequence is correlated to the request of a subset of the pin					
			//	_actualCoords = get_input_template_value<T>(pInputHiddenElement);
			//}
			_strValue = tk->read();
			return put_input_template_value<T>(_strValue, pInputHiddenElement);
		default: break;
	}
	return false;
}


bool webbot_ie::on_input_text(std::string const& _strName, std::string const& _strValue, IHTMLElementCollection* pIHTMLElementCollection)
{	
	IHTMLElement* pElem =NULL;	

	if(IHTMLInputTextElement* pInputTxtElement = get_HTML_input_text_element(_strName, pIHTMLElementCollection, &pElem))
	{
		pElem->Release();
		return put_input_template_value<IHTMLInputTextElement>(_strValue, pInputTxtElement);
	}

	return false;

}

void webbot_ie::on_input_image(const std::string& _bttnName, IHTMLElementCollection* pIHTMLElementCollection)
{
	IHTMLElement* pElem =NULL;

	if(IHTMLInputImage* pImageButton = get_HTML_input_image(_bttnName, pIHTMLElementCollection, &pElem))
	{
		pElem->click();
		pElem->Release();
	}
}

void webbot_ie::on_input_button(const std::string& _bttnName, IHTMLElementCollection* pIHTMLElementCollection)
{
	IHTMLElement* pElem =NULL;

	if(IHTMLInputButtonElement* pInputButton = get_HTML_input_button_element(_bttnName, pIHTMLElementCollection, &pElem))
	{
		pElem->click();
		pElem->Release();                                           
	}
}

void webbot_ie::on_form_action(const std::string& _formName, IHTMLElementCollection* pIHTMLElementCollection)
{
	IHTMLElement* pElem =NULL;

	if(IHTMLFormElement* pFormElement = get_HTML_form_element(_formName, pIHTMLElementCollection, &pElem))
	{
		pElem->Release();
		submit(pFormElement);
	}
}

void webbot_ie::on_jscript_action(const std::string& _formName)
{
	IDispatch* pDisp = webbot_ie::get_dispatch_interface();	

	if(IHTMLDocument2* pDoc = webbot_ie::get_HTML_document_interface(pDisp))
	{
		std::cout << "javascript: " << _formName << std::endl;

		webbot_ie::jscript(_formName, pDoc);
		pDoc->Release();
	}
	if(pDisp != NULL)	pDisp->Release();
}

bool webbot_ie::wait_ready_state_interactive()
{
	libinput input_interface;
	return input_interface.getInput()->wait_ready_state_interactive();
}


bool webbot_ie::get_post_data(LPVARIANT pvPostData)
{
	HRESULT hr;
	LPSAFEARRAY psa;
	CA2CT pszConvertedTCharString (get_url_encode().c_str());
	LPCTSTR cszPostData = pszConvertedTCharString;
	UINT cElems = lstrlen(cszPostData);
	LPSTR pPostData;

    if (!pvPostData)
    {
       return false;
    }

    VariantInit(pvPostData);

    psa = SafeArrayCreateVector(VT_UI1, 0, cElems);
    if (!psa)
    {
        return false;
    }

    hr = SafeArrayAccessData(psa, (LPVOID*)&pPostData);
    memcpy(pPostData, cszPostData, cElems);
    hr = SafeArrayUnaccessData(psa);

    V_VT(pvPostData) = VT_ARRAY | VT_UI1;
    V_ARRAY(pvPostData) = psa;

    return true;
}


std::string const webbot_ie::get_url_encode()
{
	dispatch_struct dispatch_info = get_dispatch_struct(); 
	std::vector< std::string > element_name = dispatch_info.get_input_element_name();
	std::vector< dispatch_struct::input_type > element_type = dispatch_info.get_input_element_type();	
	std::vector< std::string > element_value = dispatch_info.get_input_element_value();
	std::vector< std::string > encryption_config = dispatch_info.get_input_element_encryption();
	
	std::string url_encode_str;
	std::string tk;

	for(unsigned short j=0, k=0, l=0; j< element_name.size(); j++)
	{
		switch(element_type[j])
		{
		case dispatch_struct::TEXT:
			if(element_value.size())
			{
				k = min(element_value.size()-1, k);
				if(j>0) url_encode_str += "&";
				url_encode_str += element_name[j];
				url_encode_str += "="+element_value[k++];
			}
			break;
		case dispatch_struct::HIDDEN:
		case dispatch_struct::PASSWORD:
			k = max(0, min(encryption_config.size()-1, k));

			if(j>0) url_encode_str += "&";
			url_encode_str += element_name[j];

			tk = decrypt_token(encryption_config[k++]);
			if(tk.length())
				url_encode_str += "=" + tk;

			break;
								
		default: break;
		}
	}

	return url_encode_str;
}

std::string const webbot_ie::decrypt_token(std::string const& _encryption_config)
{
	
	libtoken tk_interface(_encryption_config.c_str());
	return tk_interface.getToken()->read();
}